package custom.cards;

import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.UUID;

import com.google.android.gcm.server.*;

import custom.cards.GameRequest.RequestType;

/**
 * @author Rich
 * 
 */
public class SocketManager
{

	private ServerSocket echoServer = null;
	private Socket clientSocket = null;
	private final int port;
	public final HashMap<String, CardGame> games = new HashMap<String, CardGame>();
	public final ArrayList<String> devices = new ArrayList<>();


	public SocketManager(int port)
	{
		this.port = port;
	}

	public void stopServer()
	{
		System.out.println("Stopping Server");
		System.exit(0);
	}

	public void startServer()
	{
		try
		{
			echoServer = new ServerSocket(port);
			System.out
					.println("Server is started and is waiting for connections. "
							+ echoServer.getInetAddress());
		}
		catch (Exception e)
		{
			System.out.println("Error Starting the Server:");
			System.out.println(e);
			return;
		}

		while (true)
		{
			try
			{
				clientSocket = echoServer.accept();
				Server2Connection oneconnection = new Server2Connection(
						clientSocket, this);
				new Thread(oneconnection).start();
			}
			catch (Exception e)
			{
				System.out.println(e);
			}
		}
	}

}

class Server2Connection implements Runnable
{
	private Socket clientSocket;
	private SocketManager server;
	private ObjectOutput oo;
	private ObjectInput ois;
	private final String APIKEY = "AIzaSyCwRUqkulXB55TLVf6vfSTuMR9llYF5VKI";

	public Server2Connection(Socket clientSocket, SocketManager server)
	{
		
		try
		{
			this.clientSocket = clientSocket;
			this.server = server;
			System.out.println("Connection established with: "
					+ clientSocket.getInetAddress());
			oo = new ObjectOutputStream(clientSocket.getOutputStream());
			ois = new ObjectInputStream(clientSocket.getInputStream());
		}
		catch (Exception e)
		{
			System.out.println(e);
		}
	}

	private final char[] set = new char[] {'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R',
										   'S','T','U','V','W','X','Y','Z','2','3','4','5','6','7','8','9'};
	
	public String getRandomString(int length) 
	{
	    StringBuilder sb = new StringBuilder();

	    for (int loop = 0; loop < length; loop++) 
	    {
	        int index = new Random().nextInt(set.length);
	        sb.append(set[index]);
	    }

	    String nonce = sb.toString();
	    return nonce;
	}
	
	@Override
	public void run()
	{
		try
		{

			GameRequest init = (GameRequest) ois.readObject();
			ois.close();
			oo.close();
			clientSocket.close();
			CardGame game;
			String gameID;
			
			Sender sender = new Sender(APIKEY);
			Message message = new Message.Builder()
					.addData("ResponseType", "None")
					.addData("Message", "No Data").build();

			switch (init.requestID)
			{

				case CreateGame:

					do
					{
						gameID = getRandomString(8);
						
					}while(server.games.containsKey(gameID));
					
					CardGame g = new CardGame(init.requestingPlayerID,init.GameName);
					
					server.games.put(gameID, g);

					
					server.games.get(gameID).AddPlayer(init.requestingPlayerID,init.playerName);
					message = new Message.Builder()
							.addData("ResponseType", "GameCreated")
							.addData("GameID", gameID)
							.build();
					Result result = sender.send(message, init.requestingPlayerID, 5);
				
					System.out.println("Player: " + init.playerName + " created game " + gameID);
					break;

				case JoinGame:

					if (server.games.containsKey(init.GameID))
					{
						
						message = new Message.Builder()
								.addData("ResponseType", "GameCreated")
								.addData("GameID", init.GameID)
								.build();
						result = sender.send(message, init.requestingPlayerID, 5);
						System.out.println("Player: " + init.playerName + " joined game " + init.GameID);
						
						server.games.get(init.GameID).AddPlayer(init.requestingPlayerID,init.playerName);

					}
					else
					{
						message = new Message.Builder()
								.addData("ResponseType", "ERROR")
								.addData("Message", "Invalid GameID").build();
						result = sender.send(message, init.requestingPlayerID, 5);

					}

					
					break;
					


				case RegID:

					if (!server.devices.contains(init.requestingPlayerID))
					{
						server.devices.add(init.requestingPlayerID);
						System.out.println(init.requestingPlayerID + " Registered");
					}

					

					break;

				default:

					if (init.GameID != null)
					{
						g = server.games.get(init.GameID);

						if (!g.players.contains(init.requestingPlayerID))
						{
							message = new Message.Builder()
									.addData("ResponseType", "ERROR")
									.addData("Message",
											"You are not a valid player in this game!")
									.build();
							result = sender.send(message, init.requestingPlayerID, 5);
						}
						else
						{
							if(!g.GameStarted && init.requestID != RequestType.StartGame && init.requestID != RequestType.SendMessage)
							{
								message = new Message.Builder()
								.addData("ResponseType", "ERROR")
								.addData("Message",
										"This game hasn't started yet.").build();
								result = sender.send(message, init.requestingPlayerID, 5);
							}
							else if (!g.GameFinished)
							{
								g.HandleRequest(init);
							}
							else
							{
								message = new Message.Builder()
										.addData("ResponseType", "ERROR")
										.addData("Message",
												"This game is over.").build();
								result = sender.send(message, init.requestingPlayerID, 5);
							}
						}

					}

					break;

			}

		}
		catch (Exception e)
		{		
			
			e.printStackTrace();
			System.out.println(e);
		}

		System.out.println("Connection Closed");
	}
}
